home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / executor / ex_qual.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  47.3 KB  |  1,806 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    ex_qual.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    Routines to evaluate qualification and targetlist expressions
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *        ExecEvalExpr    - evaluate an expression and return a datum
  10.  *        ExecQual    - return true/false if qualification is satisified
  11.  *        ExecTargetList    - form a new tuple by projecting the given tuple
  12.  *
  13.  *   NOTES
  14.  *    ExecEvalExpr() and ExecEvalVar() are hotspots.  making these faster
  15.  *    will speed up the entire system.  Unfortunately they are currently
  16.  *    implemented recursively..  Eliminating the recursion is bound to
  17.  *    improve the speed of the executor.
  18.  *
  19.  *    ExecTargetList() is used to make tuple projections.  Rather then
  20.  *    trying to speed it up, the execution plan should be pre-processed
  21.  *    to facilitate attribute sharing between nodes wherever possible,
  22.  *    instead of doing needless copying.  -cim 5/31/91
  23.  *
  24.  *   IDENTIFICATION
  25.  *    $Header: /private/postgres/src/executor/RCS/ex_qual.c,v 1.24 1992/08/25 17:46:29 mer Exp $
  26.  * ----------------------------------------------------------------
  27.  */
  28.  
  29. #include "tmp/align.h"
  30. #include "parser/parsetree.h"
  31. #include "parser/parse.h" /* for NOT used in macros in ExecEvalExpr */
  32. #include "nodes/primnodes.h"
  33. #include "nodes/relation.h"
  34. #include "planner/keys.h"
  35. #include "nodes/mnodes.h"
  36. #include "catalog/pg_language.h"
  37. #include "executor/executor.h"
  38.  RcsId("$Header: /private/postgres/src/executor/RCS/ex_qual.c,v 1.24 1992/08/25 17:46:29 mer Exp $");
  39. /* ----------------
  40.  *    externs and constants
  41.  * ----------------
  42.  */
  43.  
  44.  
  45. /*
  46.  * XXX Used so we can get rid of use of Const nodes in the executor.
  47.  * Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst
  48.  * and by ExecEvalArrayRef.
  49.  */
  50. Boolean execConstByVal;
  51. int     execConstLen;
  52.  
  53. /* ----------------
  54.  *    sysattrlen
  55.  *    sysattrbyval
  56.  *
  57.  *    these have been moved to access/tuple/tuple.c
  58.  * ----------------
  59.  */
  60.  
  61. /* --------------------------------
  62.  *    array_cast
  63.  * --------------------------------
  64.  */
  65. Datum
  66. array_cast(value, byval, len)
  67.     char *value;
  68.     bool byval;
  69.     int len;
  70. {
  71.     if (byval) {
  72.         switch (len) {
  73.     case 1:
  74.         return((Datum) * value);
  75.     case 2:
  76.         return((Datum) * (int16 *) value);
  77.     case 3:
  78.     case 4:
  79.         return((Datum) * (int32 *) value);
  80.     default:
  81.         elog(WARN, "ExecEvalArrayRef: byval and elt len > 4!");
  82.         return(NULL);
  83.             break;
  84.         }
  85.     } else
  86.         return (Datum) value;
  87. }
  88.  
  89. /* --------------------------------
  90.  *    ExecEvalArrayRef
  91.  *
  92.  *     This function takes an ArrayRef and returns a Const Node which
  93.  *     is the actual array reference. It is used to de-reference an array.
  94.  *
  95.  *  This code knows about the internal storage scheme for both fixed-length
  96.  *  arrays (like char16, int28, etc) and for variable length arrays.  It
  97.  *  currently assumes that fixed-length arrays are contiguous blobs of memory
  98.  *  where the first element is in the starting position.  Variable length
  99.  *  arrays are presumed to have the following format:
  100.  *
  101.  *  <length_in_bytes><elem_1><elem_2>...<elem_n>
  102.  *
  103.  *  It checks to see if <length_in_bytes> / <number_of_elements> = typlen
  104.  *  as a sanity check for variable length arrays.
  105.  *
  106.  *     -Greg
  107.  *
  108.  *  old comments:
  109.  *
  110.  *    XXX this code should someday handle the case where there is
  111.  *        an expression of the form:  a.b[ expression ] rather then
  112.  *        just a.b[ constant ] as it does now.  99% of this can be
  113.  *        done by using ExecEvalExpr() but it would mean some more
  114.  *        work in the parser. -cim 6/20/90
  115.  * --------------------------------
  116.  */
  117.  
  118. #define MinArrayIndirection 1
  119.  
  120. Datum
  121. ExecEvalArrayRef(arrayRef, econtext, isNull, isDone)
  122.     ArrayRef    arrayRef;
  123.     ExprContext econtext;
  124.     Boolean     *isNull;
  125.     Boolean     *isDone;
  126. {
  127.     int32    array_len;
  128.     int32    element_len;
  129.     int32    indirection;
  130.     bool    byval;
  131.     bool    dummy;
  132.     int     i;
  133.     char     *array_scanner;
  134.     int     nelems;
  135.     int        bytes;
  136.     int        nbytes;
  137.     int        offset;
  138.     bool     done = false;
  139.     char     *retval;
  140.     
  141.     *isNull       =    false;
  142.     array_scanner =    (char *)ExecEvalExpr((Node)get_refexpr(arrayRef),
  143.                          econtext,
  144.                          isNull,
  145.                          isDone);
  146.     if (*isNull)
  147.     return (Datum)NULL;
  148.     /*
  149.      * Array indices *cannot* be sets and are 1 based (convert to 0 based).
  150.      */
  151.     indirection = (int32)ExecEvalExpr((Node)get_refindexpr(arrayRef),
  152.                       econtext,
  153.                       isNull,
  154.                       &dummy);
  155.     if (*isNull)
  156.     return (Datum)NULL;
  157.  
  158.     if (indirection < MinArrayIndirection)
  159.     {
  160.     *isNull = true;
  161.     return (Datum)NULL;
  162.     }
  163.     indirection--;
  164.  
  165.     byval = execConstByVal = get_refelembyval(arrayRef);
  166.     element_len    = get_refelemlength(arrayRef);
  167.     
  168.     if (get_refattrlength(arrayRef) < 0)
  169.     {
  170.     nbytes = (* (int32 *) array_scanner) - sizeof(int32);
  171.     array_scanner += sizeof(int32);
  172.     }
  173.     else
  174.     nbytes = get_refattrlength(arrayRef);
  175.     
  176.     if (element_len < 0) {
  177.     bytes = nbytes;
  178.     i = 0;
  179.     while (bytes > 0 && !done) {
  180.         if (i == indirection) {
  181.         retval = array_scanner;
  182.         done = true;
  183.         }
  184.         bytes -= LONGALIGN(* (int32 *) array_scanner);
  185.         array_scanner += LONGALIGN(* (int32 *) array_scanner);
  186.         i++;
  187.     }
  188.         
  189.     if (! done) {
  190.         if (bytes == 0) { /* array[i] does not exist */
  191.         *isNull = true;
  192.         return(NULL);
  193.         } else { /* bytes < 0 - error */
  194.         elog(WARN, "ExecEvalArrayRef: improperly formatted array");
  195.         }
  196.     }
  197.     return (Datum) retval;
  198.         
  199.     } else {
  200.     /* array of fixed length elements */
  201.         
  202.     offset = indirection * element_len;
  203.         
  204.     /*
  205.      * off the end of the array
  206.      */
  207.     if (nbytes - offset < 1) {
  208.         *isNull = true;
  209.         return(NULL);
  210.     }
  211.         
  212.     retval = array_scanner + offset;
  213.         
  214.     return array_cast(retval, byval, element_len);
  215.     }
  216. }
  217.  
  218. Datum
  219. ExecExtractResult(slot, attnum, isNull)
  220.     TupleTableSlot  slot;
  221.     AttributeNumber attnum;
  222.     Boolean         *isNull;
  223. {
  224.     ExecTupDescriptor    execTd;
  225.     TupleDescriptor    td;
  226.     HeapTuple        tuple;
  227.     Buffer        buffer;
  228.     DatumPtr        values;
  229.     char        *nullVect;  
  230.     int            count;
  231.     int            subTupNatts;
  232.     AttributeNumber    subTupAtt;
  233.     TupleTableSlot    resultSlot;
  234.  
  235.     execTd = SlotExecTupDescriptor(slot);
  236.  
  237.     *isNull = false;
  238.     subTupNatts = execTd->data[attnum-1]->len;
  239.     td = ExecSlotDescriptor(slot);
  240.     tuple = (HeapTuple)ExecFetchTuple(slot);
  241.     buffer = ExecSlotBuffer(slot);
  242.  
  243.     values = (DatumPtr)palloc(subTupNatts*sizeof(Datum));
  244.     nullVect = (char *)palloc(subTupNatts*sizeof(char));
  245.  
  246.     /*
  247.      * Figure out where in the context of the larger tuple to begin
  248.      * searching for the sub tuples attributes.  Note that attribute
  249.      * numbers are 1 based.
  250.      */
  251.     count = 0;
  252.     subTupAtt = 1;
  253.     while (count < (attnum-1))
  254.     subTupAtt += execTd->data[count++]->len;
  255.  
  256.     count = 0;
  257.     while (count < subTupNatts)
  258.     {
  259.     bool attrIsNull;
  260.  
  261.     values[count] = (Datum)
  262.         heap_getattr(tuple,
  263.              buffer,
  264.              subTupAtt,
  265.              (struct attribute **)&td->data[0],
  266.              &attrIsNull);
  267.     
  268.     if (attrIsNull)
  269.         nullVect[count] = 'n';
  270.     else
  271.         nullVect[count] = ' ';
  272.     
  273.     count++;
  274.     subTupAtt++;
  275.     }
  276.  
  277.     td = execTd->data[attnum-1]->attdesc;
  278.     tuple = heap_formtuple(subTupNatts, td, values, nullVect);
  279.     resultSlot = MakeTupleTableSlot(false,
  280.                     true,
  281.                     ExecCopyTupType(td, subTupNatts),
  282.                     NULL,
  283.                     InvalidBuffer,
  284.                     -1);
  285.     return (Datum)
  286.     ExecStoreTuple((Pointer) tuple,
  287.                (Pointer) resultSlot,
  288.                InvalidBuffer,
  289.                true);
  290. }
  291. /* ----------------------------------------------------------------
  292.  *        ExecEvalVar
  293.  *    
  294.  *        Returns a Datum whose value is the value of a range
  295.  *    variable with respect to given expression context.
  296.  * ----------------------------------------------------------------
  297.  */
  298.  
  299. /**** xxref:
  300.  *           ExecEvalExpr
  301.  ****/
  302. Datum
  303. ExecEvalVar(variable, econtext, isNull)
  304.     Var     variable;
  305.     ExprContext econtext;
  306.     Boolean     *isNull;
  307. {
  308.     Datum            result;
  309.     TupleTableSlot      slot;
  310.     AttributeNumber     attnum;
  311.     TupleDescriptor        tupType;
  312.     ExecTupDescriptor    execTupDesc;
  313.     Buffer            tupBuffer;
  314.     List            array_info;
  315.     
  316.     HeapTuple        heapTuple;
  317.     TupleDescriptor    tuple_type;
  318.     Buffer         buffer;
  319.     ObjectId        typeoid;
  320.     bool        byval;
  321.     Pointer        value;
  322.     int16           len;
  323.  
  324.     /* ----------------
  325.      *    get the slot we want
  326.      * ----------------
  327.      */
  328.     switch(get_varno(variable)) {
  329.     case INNER: /* get the tuple from the inner node */
  330.     slot = get_ecxt_innertuple(econtext);
  331.     break;
  332.         
  333.     case OUTER: /* get the tuple from the outer node */
  334.     slot = get_ecxt_outertuple(econtext);
  335.     break;
  336.  
  337.     default: /* get the tuple from the relation being scanned */
  338.     slot = get_ecxt_scantuple(econtext);
  339.     break;
  340.     } 
  341.  
  342.     /* ----------------
  343.      *   extract tuple information from the slot
  344.      * ----------------
  345.      */
  346.     heapTuple = (HeapTuple) ExecFetchTuple((Pointer) slot);
  347.     tuple_type =         ExecSlotDescriptor((Pointer)slot);
  348.     buffer =            ExecSlotBuffer((Pointer)slot);
  349.     
  350.     attnum =      get_varattno(variable);
  351.         
  352.     /*
  353.      * If the attribute number is invalid, then we are supposed to
  354.      * return the entire tuple, we give back a whole slot so that
  355.      * callers know what the tuple looks like.
  356.      */
  357.     if (attnum == InvalidAttributeNumber)
  358.     {
  359.     TupleTableSlot  tempSlot;
  360.     TupleDescriptor td;
  361.     HeapTuple       tup;
  362.  
  363.     tempSlot = MakeTupleTableSlot(false,
  364.                       true,
  365.                       (TupleDescriptor)NULL,
  366.                       (ExecTupDescriptor)NULL,
  367.                       InvalidBuffer,
  368.                       -1);
  369.  
  370.     tup = (HeapTuple)heap_copysimple(ExecFetchTuple(slot));
  371.     td = (TupleDescriptor)
  372.         ExecCopyTupType(ExecSlotDescriptor(slot), tup->t_natts);
  373.     ExecSetSlotDescriptor((Pointer)tempSlot, td);
  374.  
  375.     ExecStoreTuple((Pointer)tup, (Pointer)tempSlot, InvalidBuffer, true);
  376.     return (Datum) tempSlot;
  377.     }
  378.  
  379.     /* ----------------
  380.      *    get the attribute our of the tuple.  Note that
  381.      *  now the attribute could be much more than a simple datum.
  382.      * ----------------
  383.      */
  384.     execTupDesc = SlotExecTupDescriptor(slot);
  385.     if (execTupDesc != (ExecTupDescriptor)NULL &&
  386.     AttributeNumberIsForUserDefinedAttribute(attnum) &&
  387.     execTupDesc->data[attnum-1]->tag == ATTTUP)
  388.     {
  389.     result = ExecExtractResult(slot, attnum, isNull);
  390.     }
  391.     else
  392.     {
  393.     result =  (Datum)
  394.         heap_getattr(heapTuple,  /* tuple containing attribute */
  395.                  buffer,     /* buffer associated with tuple */
  396.                  attnum,     /* attribute number of desired attribute */
  397.                  tuple_type, /* tuple descriptor of tuple */
  398.                  isNull);    /* return: is attribute null? */
  399.     }
  400.  
  401.     /* ----------------
  402.      *    return null if att is null
  403.      * ----------------
  404.      */
  405.     if (*isNull)
  406.     return NULL;
  407.     
  408.     /* ----------------
  409.      *   get length and type information..
  410.      *   ??? what should we do about variable length attributes
  411.      *     - variable length attributes have their length stored
  412.      *     in the first 4 bytes of the memory pointed to by the
  413.      *     returned value.. If we can determine that the type
  414.      *     is a variable length type, we can do the right thing.
  415.      *       -cim 9/15/89
  416.      * ----------------
  417.      */
  418.     if (attnum < 0) {
  419.     /* ----------------
  420.      *  If this is a pseudo-att, we get the type and fake the length.
  421.      *  There ought to be a routine to return the real lengths, so
  422.      *  we'll mark this one ... XXX -mao
  423.      * ----------------
  424.      */
  425.         len =     sysattrlen(attnum);      /* XXX see -mao above */
  426.     byval = sysattrbyval(attnum);    /* XXX see -mao above */
  427.     } else {
  428.         len =   tuple_type->data[ attnum-1 ]->attlen;
  429.     byval = tuple_type->data[ attnum-1 ]->attbyval ? true : false ;
  430.     }
  431.  
  432.     execConstByVal = byval;
  433.     execConstLen =   len;
  434.  
  435.     return result;
  436. }
  437.  
  438. /* ----------------------------------------------------------------
  439.  *      ExecEvalParam
  440.  *
  441.  *      Returns the value of a parameter.  A param node contains
  442.  *    something like ($.name) and the expression context contains
  443.  *    the current parameter bindings (name = "sam") (age = 34)...
  444.  *    so our job is to replace the param node with the datum
  445.  *    containing the appropriate information ("sam").
  446.  *
  447.  *    Q: if we have a parameter ($.foo) without a binding, i.e.
  448.  *       there is no (foo = xxx) in the parameter list info,
  449.  *       is this a fatal error or should this be a "not available"
  450.  *       (in which case we shoud return a Const node with the
  451.  *        isnull flag) ?  -cim 10/13/89
  452.  *
  453.  *      Minor modification: Param nodes now have an extra field,
  454.  *      `paramkind' which specifies the type of parameter 
  455.  *      (see params.h). So while searching the paramList for
  456.  *      a paramname/value pair, we have also to check for `kind'.
  457.  *     
  458.  *      NOTE: The last entry in `paramList' is always an
  459.  *      entry with kind == PARAM_INVALID.
  460.  * ----------------------------------------------------------------
  461.  */
  462. /**** xxref:
  463.  *           ExecEvalExpr
  464.  ****/
  465. Datum
  466. ExecEvalParam(expression, econtext, isNull)
  467.     Param     expression;
  468.     ExprContext econtext;
  469.     Boolean     *isNull;
  470. {
  471.  
  472.     Name           thisParameterName;
  473.     int              thisParameterKind;
  474.     AttributeNumber    thisParameterId;
  475.     int         i;
  476.     int           matchFound;
  477.     Const         constNode;
  478.     ParamListInfo    paramList;
  479.     
  480.     thisParameterName = get_paramname(expression);
  481.     thisParameterKind = get_paramkind(expression);
  482.     thisParameterId =   get_paramid(expression);
  483.     paramList =     get_ecxt_param_list_info(econtext);
  484.     
  485.     *isNull = false;
  486.     /*
  487.      * search the list with the parameter info to find a matching name.
  488.      * An entry with an InvalidName denotes the last element in the array.
  489.      */
  490.     matchFound = 0;
  491.     if (paramList != NULL) {
  492.     /*
  493.      * search for an entry in 'paramList' that matches
  494.      * the `expression'.
  495.      */
  496.     while(paramList->kind != PARAM_INVALID && !matchFound) {
  497.         switch (thisParameterKind) {
  498.         case PARAM_NAMED:
  499.             if (thisParameterKind == paramList->kind &&
  500.                 NameIsEqual(paramList->name, thisParameterName)){
  501.                 matchFound = 1;
  502.             } 
  503.             break;
  504.         case PARAM_NUM:
  505.             if (thisParameterKind == paramList->kind &&
  506.             paramList->id == thisParameterId) {
  507.                 matchFound = 1;
  508.             }
  509.             break;
  510.         case PARAM_OLD:
  511.         case PARAM_NEW:
  512.             if (thisParameterKind == paramList->kind &&
  513.             paramList->id == thisParameterId)
  514.             {
  515.             matchFound = 1;
  516.             /*
  517.              * sanity check
  518.              */
  519.                 if (! NameIsEqual(paramList->name, thisParameterName)){
  520.                 elog(WARN,
  521.         "ExecEvalParam: new/old params with same id & diff names");
  522.             }
  523.             }
  524.             break;
  525.         default:
  526.             /*
  527.              * oops! this is not supposed to happen!
  528.              */
  529.             elog(WARN, "ExecEvalParam: invalid paramkind %d",
  530.             thisParameterKind);
  531.         }
  532.         if (! matchFound) {
  533.         paramList++;
  534.         }
  535.     } /*while*/
  536.     } /*if*/
  537.     
  538.     if (!matchFound) {
  539.     /*
  540.      * ooops! we couldn't find this parameter
  541.      * in the parameter list. Signal an error
  542.      */
  543.     elog(WARN, "ExecEvalParam: Unknown value for parameter %s",
  544.          thisParameterName);
  545.     }
  546.     
  547.     /*
  548.      * return the value.
  549.      */
  550.     if (paramList->isnull)
  551.     {
  552.     *isNull = true;
  553.     return (Datum)NULL;
  554.     }
  555.  
  556.     if (get_param_tlist(expression) != (List)NULL)
  557.     {
  558.     HeapTuple      tup;
  559.     Datum          value;
  560.     List           tlist = get_param_tlist(expression);
  561.     List           tle  = CAR(tlist);
  562.     TupleTableSlot slot = (TupleTableSlot)paramList->value;
  563.  
  564.     tup = (HeapTuple)ExecFetchTuple((Pointer)slot);
  565.     value = ProjectAttribute(ExecSlotDescriptor(slot), tle, tup, isNull);
  566.     return value;
  567.     }
  568.     return(paramList->value);
  569. }
  570.  
  571.  
  572. /* ----------------------------------------------------------------
  573.  *        ExecEvalOper / ExecEvalFunc support routines
  574.  * ----------------------------------------------------------------
  575.  */
  576.  
  577. /* ----------------
  578.  *    GetAttributeByName
  579.  *    GetAttributeByNum
  580.  *
  581.  *    These are functions which return the value of the
  582.  *    named attribute out of the tuple from the arg slot.  User defined
  583.  *    C functions which take a tuple as an argument are expected
  584.  *    to use this.  Ex: overpaid(EMP) might call GetAttributeByNum().
  585.  * ----------------
  586.  */
  587.  
  588. GetAttributeByNum(slot, attrno, isNull)
  589.     TupleTableSlot slot;
  590.     AttributeNumber attrno;
  591.     Boolean *isNull;
  592. {
  593.     Datum retval;
  594.  
  595.     if (!AttributeNumberIsValid(attrno))
  596.     elog(WARN, "GetAttributeByNum: Invalid attribute number");
  597.     
  598.     if (!AttributeNumberIsForUserDefinedAttribute(attrno))
  599.     elog(WARN, "GetAttributeByNum: cannot access system attributes here");
  600.  
  601.     if (isNull == (Boolean *)NULL)
  602.     elog(WARN, "GetAttributeByNum: a NULL isNull flag was passed");
  603.     
  604.     if (TupIsNull((Pointer)slot))
  605.     {
  606.         *isNull = true;
  607.     return;
  608.     }
  609.  
  610.     retval = (Datum)
  611.     heap_getattr(ExecFetchTuple(slot),
  612.              ExecSlotBuffer(slot),
  613.              attrno,
  614.              ExecSlotDescriptor(slot),
  615.              isNull);
  616.     if (*isNull)
  617.     return NULL;
  618.     else
  619.     return retval;
  620. }
  621.  
  622. GetAttributeByName(slot, attname, isNull)
  623.     TupleTableSlot slot;
  624.     Name    attname;
  625.     Boolean *isNull;
  626. {
  627.     AttributeNumber attrno;
  628.     TupleDescriptor tupdesc;
  629.     HeapTuple       tuple;
  630.     ObjectId relid;
  631.     Datum retval;
  632.     int natts;
  633.     int i;
  634.  
  635.     if (attname == (Name)NULL)
  636.     elog(WARN, "GetAttributeByName: Invalid attribute name");
  637.     
  638.     if (isNull == (Boolean *)NULL)
  639.     elog(WARN, "GetAttributeByName: a NULL isNull flag was passed");
  640.     
  641.     if (TupIsNull((Pointer)slot))
  642.     {
  643.         *isNull = true;
  644.     return;
  645.     }
  646.  
  647.     tupdesc = ExecSlotDescriptor(slot);
  648.     tuple = (HeapTuple)ExecFetchTuple(slot);
  649.  
  650.     natts = tuple->t_natts;
  651.  
  652.     i = 0;
  653.     attrno = InvalidAttributeNumber;
  654.     while (i < natts)
  655.     {
  656.     /*
  657.      * Given a slot we really don't know how many attributes
  658.      * we have in the tuple, so I chose to use a completely
  659.      * bogus check looking right into bogus memory.  I can't
  660.      * think of a reasonable way to do this and it is getting
  661.      * late. I apologize to future post-boys and post-girls -mer
  662.      */
  663.     if (strncmp(attname,
  664.             &(tupdesc->data[i]->attname),
  665.             sizeof(NameData)) == 0)
  666.     {
  667.         attrno = tupdesc->data[i]->attnum;
  668.         break;
  669.     }
  670.     i++;
  671.     }
  672.     
  673.     if (attrno == InvalidAttributeNumber)
  674.     elog(WARN, "GetAttributeByName: attribute %s not found", attname);
  675.  
  676.     retval = (Datum)
  677.     heap_getattr(ExecFetchTuple(slot),
  678.              ExecSlotBuffer(slot),
  679.              attrno,
  680.              tupdesc,
  681.              isNull);
  682.     if (*isNull)
  683.     return NULL;
  684.     else
  685.     return retval;
  686. }
  687.  
  688. void
  689. ExecEvalFuncArgs(fcache, econtext, argList, argV, argIsDone)
  690.     FunctionCachePtr fcache;
  691.     ExprContext econtext;
  692.     List argList;
  693.     Datum argV[];
  694.     Boolean *argIsDone;
  695. {
  696.     int i;
  697.     bool      argIsNull, *nullVect;
  698.     LispValue arg;
  699.  
  700.     nullVect = fcache->nullVect;
  701.  
  702.     i = 0;
  703.     foreach (arg, argList) {
  704.     /* ----------------
  705.      *   evaluate the expression, in general functions cannot take
  706.      *   sets as arguments but we make an exception in the case of
  707.      *   nested dot expressions.  We have to watch out for this case
  708.      *   here.
  709.      * ----------------
  710.      */
  711.     argV[i] = (Datum)
  712.         ExecEvalExpr((Node) CAR(arg),
  713.                  econtext,
  714.                  &argIsNull,
  715.                  argIsDone);
  716.     if (! (*argIsDone))
  717.     {
  718.         Assert(i == 0);
  719.         fcache->setArg = (char *)argV[0];
  720.         fcache->hasSetArg = true;
  721.     }
  722.     if (argIsNull)
  723.         nullVect[i] = true;
  724.     else
  725.         nullVect[i] = false;
  726.     i++;
  727.     }
  728. }
  729.  
  730. /* ----------------
  731.  *    ExecMakeFunctionResult
  732.  * ----------------
  733.  */
  734. Datum
  735. ExecMakeFunctionResult(node, arguments, econtext, isNull, isDone)
  736.     Node    node;
  737.     List     arguments;
  738.     ExprContext econtext;
  739.     Boolean *isNull;
  740.     Boolean *isDone;
  741. {
  742.     List    arg;
  743.     Datum    argv[MAXFMGRARGS];
  744.     FunctionCachePtr fcache;
  745.     Func    funcNode = NULL;
  746.     Oper    operNode = NULL;
  747.  
  748.     /*
  749.      * This is kind of ugly, Func nodes now have targetlists so that
  750.      * we know when and what to project out from postquel function results.
  751.      * This means we have to pass the func node all the way down instead
  752.      * of using only the fcache struct as before.  ExecMakeFunctionResult
  753.      * becomes a little bit more of a dual personality as a result.
  754.      */
  755.     if (ExactNodeType(node,Func))
  756.     {
  757.     funcNode = (Func)node;
  758.     fcache = get_func_fcache(funcNode);
  759.     }
  760.     else
  761.     {
  762.     operNode = (Oper)node;
  763.     fcache = get_op_fcache(operNode);
  764.     }
  765.  
  766.     /* ----------------
  767.      *    arguments is a list of expressions to evaluate
  768.      *  before passing to the function manager.
  769.      *  We collect the results of evaluating the expressions
  770.      *  into a datum array (argv) and pass this array to arrayFmgr()
  771.      * ----------------
  772.      */
  773.     if (fcache->nargs != 0) {
  774.     bool argDone;
  775.  
  776.     if (fcache->nargs > MAXFMGRARGS) 
  777.         elog(WARN, "ExecMakeFunctionResult: too many arguments");
  778.  
  779.     /*
  780.      * If the setArg in the fcache is set we have an argument
  781.      * returning a set of tuples (i.e. a nested dot expression).  We
  782.      * don't want to evaluate the arguments again until the function
  783.      * is done. hasSetArg will always be false until we eval the args
  784.      * for the first time. We should set this in the parser.
  785.      */
  786.     if ((fcache->hasSetArg) && fcache->setArg != NULL)
  787.     {
  788.         argv[0] = (Datum)fcache->setArg;
  789.         argDone = false;
  790.     }
  791.     else
  792.         ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
  793.  
  794.     if ((fcache->hasSetArg) && (argDone)) {
  795.         if (isDone) *isDone = true;
  796.         return (Datum)NULL;
  797.     }
  798.     }
  799.  
  800.     /* ----------------
  801.      *   now return the value gotten by calling the function manager, 
  802.      *   passing the function the evaluated parameter values. 
  803.      * ----------------
  804.      */
  805.     if (fcache->language == POSTQUELlanguageId) {
  806.     Datum result;
  807.  
  808.     Assert(funcNode);
  809.     result = postquel_function (funcNode, argv, isNull, isDone);
  810.     /*
  811.      * finagle the situation where we are iterating through all results
  812.      * in a nested dot function (whose argument function returns a set
  813.      * of tuples) and the current function finally finishes.  We need to
  814.      * get the next argument in the set and run the function all over
  815.      * again.  This is getting unclean.
  816.      */
  817.     if ((*isDone) && (fcache->hasSetArg)) {
  818.         Boolean argDone;
  819.  
  820.         ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
  821.  
  822.         if (argDone) {
  823.             fcache->setArg = (char *)NULL;
  824.         *isDone = true;
  825.         result = (Datum)NULL;
  826.         }
  827.         else
  828.         result = postquel_function(funcNode,
  829.                        argv,
  830.                        isNull,
  831.                        isDone,
  832.                        &argDone);
  833.     }
  834.     return result;
  835.     }
  836.     else 
  837.     {
  838.     int i;
  839.  
  840.     if (isDone) *isDone = true;
  841.     for (i = 0; i < fcache->nargs; i++) 
  842.         if (fcache->nullVect[i] == true) *isNull = true;
  843.  
  844.     return (Datum)
  845.         fmgr_by_ptr_array_args(fcache->func, fcache->nargs, argv, isNull);
  846.     }
  847. }
  848.  
  849.  
  850. /* ----------------------------------------------------------------
  851.  *        ExecEvalOper
  852.  *        ExecEvalFunc
  853.  *    
  854.  *        Evaluate the functional result of a list of arguments by calling the
  855.  *        function manager.  Note that in the case of operator expressions, the
  856.  *        optimizer had better have already replaced the operator OID with the
  857.  *        appropriate function OID or we're hosed.
  858.  *
  859.  * old comments
  860.  *        Presumably the function manager will not take null arguments, so we
  861.  *        check for null arguments before sending the arguments to (fmgr).
  862.  *    
  863.  *        Returns the value of the functional expression.
  864.  * ----------------------------------------------------------------
  865.  */
  866.   
  867. /* ----------------------------------------------------------------
  868.  *    ExecEvalOper
  869.  * ----------------------------------------------------------------
  870.  */
  871. /**** xxref:
  872.  *           ExecEvalExpr
  873.  ****/
  874.  
  875. Datum
  876. ExecEvalOper(opClause, econtext, isNull)
  877.     List        opClause;
  878.     ExprContext econtext;
  879.     Boolean     *isNull;
  880. {
  881.     Oper    op; 
  882.     List    argList;
  883.     FunctionCachePtr fcache;
  884.     bool    isDone;
  885.     
  886.     /* ----------------
  887.      *  an opclause is a list (op args).  (I think)
  888.      *
  889.      *  we extract the oid of the function associated with
  890.      *  the op and then pass the work onto ExecMakeFunctionResult
  891.      *  which evaluates the arguments and returns the result of
  892.      *  calling the function on the evaluated arguments.
  893.      * ----------------
  894.      */
  895.     op =     (Oper) get_op(opClause);
  896.     argList =   (List) get_opargs(opClause);
  897.  
  898.     /*
  899.      * get the fcache from the Oper node.
  900.      * If it is NULL, then initialize it
  901.      */
  902.     fcache = get_op_fcache(op);
  903.     if (fcache == NULL) {
  904.         set_fcache(op, get_opid(op), cdr(opClause), econtext);
  905.         fcache = get_op_fcache(op);
  906.     }
  907.     
  908.     /* -----------
  909.      *  call ExecMakeFunctionResult() with a dummy isDone that we ignore.
  910.      *  We don't have operator whose arguments are sets.
  911.      * -----------
  912.      */
  913.     return
  914.     ExecMakeFunctionResult((Node)op, argList, econtext, isNull, &isDone);
  915. }
  916.  
  917. /* ----------------------------------------------------------------
  918.  *    ExecEvalFunc
  919.  * ----------------------------------------------------------------
  920.  */
  921.  
  922. /**** xxref:
  923.  *           ExecEvalExpr
  924.  ****/
  925. Datum
  926. ExecEvalFunc(funcClause, econtext, isNull, isDone)
  927.     LispValue   funcClause;
  928.     ExprContext econtext;
  929.     Boolean     *isNull;
  930.     Boolean     *isDone;
  931. {
  932.     Func    func;
  933.     List    argList;
  934.     FunctionCachePtr fcache;
  935.     
  936.     /* ----------------
  937.      *  an funcclause is a list (func args).  (I think)
  938.      *
  939.      *  we extract the oid of the function associated with
  940.      *  the func node and then pass the work onto ExecMakeFunctionResult
  941.      *  which evaluates the arguments and returns the result of
  942.      *  calling the function on the evaluated arguments.
  943.      *
  944.      *  this is nearly identical to the ExecEvalOper code.
  945.      * ----------------
  946.      */
  947.     func =    (Func) get_function(funcClause);
  948.     argList =   (List) get_funcargs(funcClause);
  949.  
  950.     /*
  951.      * get the fcache from the Func node.
  952.      * If it is NULL, then initialize it
  953.      */
  954.     fcache = get_func_fcache(func);
  955.     if (fcache == NULL) {
  956.         set_fcache(func, get_funcid(func), CDR(funcClause), econtext);
  957.         fcache = get_func_fcache(func);
  958.     }
  959.  
  960.     return
  961.     ExecMakeFunctionResult((Node)func, argList, econtext, isNull, isDone);
  962. }
  963.  
  964. /* ----------------------------------------------------------------
  965.  *        ExecEvalNot
  966.  *        ExecEvalOr
  967.  *    ExecEvalAnd
  968.  *    
  969.  *        Evaluate boolean expressions.  Evaluation of 'or' is
  970.  *    short-circuited when the first true (or null) value is found.
  971.  *
  972.  *    The query planner reformulates clause expressions in the
  973.  *    qualification to conjunctive normal form.  If we ever get
  974.  *    an AND to evaluate, we can be sure that it's not a top-level
  975.  *    clause in the qualification, but appears lower (as a function
  976.  *    argument, for example), or in the target list.  Not that you
  977.  *    need to know this, mind you...
  978.  * ----------------------------------------------------------------
  979.  */
  980. /**** xxref:
  981.  *           ExecEvalExpr
  982.  ****/
  983. Datum
  984. ExecEvalNot(notclause, econtext, isNull)
  985.     List     notclause;
  986.     ExprContext econtext;
  987.     Boolean     *isNull;
  988. {
  989.     Datum expr_value;
  990.     Datum const_value;
  991.     List  clause;
  992.     bool  isDone;
  993.  
  994.     clause =      (List) get_notclausearg(notclause);
  995.  
  996.     /* ----------------
  997.      *  We don't iterate over sets in the quals, so pass in an isDone
  998.      *  flag, but ignore it.
  999.      * ----------------
  1000.      */
  1001.     expr_value = ExecEvalExpr((Node) clause, econtext, isNull, &isDone);
  1002.  
  1003.     /* ----------------
  1004.      *    if the expression evaluates to null, then we just
  1005.      *  cascade the null back to whoever called us.
  1006.      * ----------------
  1007.      */
  1008.     if (*isNull)
  1009.     return expr_value;
  1010.     
  1011.     /* ----------------
  1012.      *  evaluation of 'not' is simple.. expr is false, then
  1013.      *  return 'true' and vice versa.
  1014.      * ----------------
  1015.      */
  1016.     if (ExecCFalse(DatumGetInt32(expr_value)))
  1017.     return (Datum) true;
  1018.    
  1019.     return (Datum) false;
  1020. }
  1021.  
  1022. /* ----------------------------------------------------------------
  1023.  *    ExecEvalOr
  1024.  * ----------------------------------------------------------------
  1025.  */
  1026.  
  1027. /**** xxref:
  1028.  *           ExecEvalExpr
  1029.  ****/
  1030. Datum
  1031. ExecEvalOr(orExpr, econtext, isNull)
  1032.     List     orExpr;
  1033.     ExprContext econtext;
  1034.     Boolean *isNull;
  1035. {
  1036.     List   clauses;
  1037.     List   clause;
  1038.     Datum  const_value;
  1039.     bool   isDone;
  1040.     Boolean IsNull;
  1041.  
  1042.     IsNull = false; 
  1043.     clauses = (List) get_orclauseargs(orExpr);
  1044.  
  1045.     /* ----------------
  1046.      *  we use three valued logic functions here...
  1047.      *    we evaluate each of the clauses in turn,
  1048.      *  as soon as one is true we return that
  1049.      *  value.  If none is true and  none of the
  1050.      *  clauses evaluate to NULL we return
  1051.      *  the value of the last clause evaluated (which
  1052.      *  should be false) with *isNull set to false else 
  1053.      *  if none is true and at least one clause evaluated
  1054.      *  to NULL we set *isNull flag to true -  
  1055.      * ----------------
  1056.      */
  1057.     foreach (clause, clauses) {
  1058.  
  1059.     /* ----------------
  1060.      *  We don't iterate over sets in the quals, so pass in an isDone
  1061.      *  flag, but ignore it.
  1062.      * ----------------
  1063.      */
  1064.     const_value = ExecEvalExpr((Node) CAR(clause),
  1065.                    econtext,
  1066.                    isNull,
  1067.                    &isDone);
  1068.     
  1069.     /* ----------------
  1070.      *  if the expression evaluates to null, then we 
  1071.      *  remember it in the local IsNull flag, if none of the
  1072.      *  clauses are true then we need to set *isNull
  1073.      *  to true again.
  1074.      * ----------------
  1075.      */
  1076.     if (*isNull)
  1077.         IsNull = *isNull;
  1078.     
  1079.     /* ----------------
  1080.      *   if we have a true result, then we return it.
  1081.      * ----------------
  1082.      */
  1083.     if (! ExecCFalse(DatumGetInt32(const_value)))
  1084.         return const_value;
  1085.     }
  1086.  
  1087.     /* IsNull is true if at least one clause evaluated to NULL */    
  1088.     *isNull = IsNull;
  1089.     return const_value;
  1090. }
  1091.  
  1092. /* ----------------------------------------------------------------
  1093.  *    ExecEvalAnd
  1094.  * ----------------------------------------------------------------
  1095.  */
  1096.  
  1097. /**** xxref:
  1098.  *           ExecEvalExpr
  1099.  ****/
  1100. Datum
  1101. ExecEvalAnd(andExpr, econtext, isNull)
  1102.     List     andExpr;
  1103.     ExprContext econtext;
  1104.     Boolean *isNull;
  1105. {
  1106.     List   clauses;
  1107.     List   clause;
  1108.     Datum  const_value;
  1109.     bool   isDone;
  1110.     Boolean IsNull;
  1111.  
  1112.     IsNull = false;
  1113.  
  1114.     clauses = (List) get_andclauseargs(andExpr);
  1115.  
  1116.     /* ----------------
  1117.      *    we evaluate each of the clauses in turn,
  1118.      *  as soon as one is false we return that
  1119.      *  value.  If none are false or NULL then we return
  1120.      *  the value of the last clause evaluated, which
  1121.      *  should be true. 
  1122.      * ----------------
  1123.      */
  1124.     foreach (clause, clauses) {
  1125.  
  1126.     /* ----------------
  1127.      *  We don't iterate over sets in the quals, so pass in an isDone
  1128.      *  flag, but ignore it.
  1129.      * ----------------
  1130.      */
  1131.     const_value = ExecEvalExpr((Node) CAR(clause),
  1132.                    econtext,
  1133.                    isNull,
  1134.                    &isDone);
  1135.     
  1136.     /* ----------------
  1137.      *  if the expression evaluates to null, then we 
  1138.      *  remember it in IsNull, if none of the clauses after
  1139.      *  this evaluates to false we will have to set *isNull
  1140.      *  to true again.
  1141.      * ----------------
  1142.      */
  1143.     if (*isNull)
  1144.         IsNull = *isNull;
  1145.     
  1146.     /* ----------------
  1147.      *   if we have a false result, then we return it, since the
  1148.      *   conjunction must be false.
  1149.      * ----------------
  1150.      */
  1151.     if (ExecCFalse(DatumGetInt32(const_value)))
  1152.         return const_value;
  1153.     }
  1154.  
  1155.     *isNull = IsNull;
  1156.     return const_value;
  1157. }
  1158.  
  1159. /* ----------------------------------------------------------------  
  1160.  *        ExecEvalExpr
  1161.  *    
  1162.  *        Recursively evaluate a targetlist or qualification expression.
  1163.  *
  1164.  *        This routine is an inner loop routine and should be as fast
  1165.  *      as possible.
  1166.  *
  1167.  *      Node comparison functions were replaced by macros for speed and to plug
  1168.  *      memory leaks incurred by using the planner's Lispy stuff for
  1169.  *      comparisons.  Order of evaluation of node comparisons IS IMPORTANT;
  1170.  *      the macros do no checks.  Order of evaluation:
  1171.  *      
  1172.  *      o an isnull check, largely to avoid coredumps since greg doubts this
  1173.  *        routine is called with a null ptr anyway in proper operation, but is
  1174.  *        not completely sure...
  1175.  *      o ExactNodeType checks.
  1176.  *      o clause checks or other checks where we look at the CAR of something.
  1177.  * ----------------------------------------------------------------
  1178.  */
  1179. Datum
  1180. ExecEvalExpr(expression, econtext, isNull, isDone)
  1181.     Node     expression;
  1182.     ExprContext econtext;
  1183.     Boolean     *isNull;
  1184.     Boolean     *isDone;
  1185. {
  1186.     Datum retDatum;
  1187.  
  1188.     *isNull = false;
  1189.  
  1190.     /*
  1191.      * Some callers don't care about is done and only want 1 result.  They
  1192.      * indicate this by passing NULL
  1193.      */
  1194.     if (isDone)
  1195.     *isDone = true;
  1196.  
  1197.     /* ----------------
  1198.      *    here we dispatch the work to the appropriate type
  1199.      *  of function given the type of our expression.
  1200.      * ----------------
  1201.     */
  1202.     if (expression == NULL) {
  1203.     *isNull = true;
  1204.     retDatum = (Datum) true;
  1205.     } else if (ExactNodeType(expression,Var))
  1206.     retDatum = (Datum) ExecEvalVar((Var) expression, econtext, isNull);
  1207.    
  1208.     else if (ExactNodeType(expression,Const)) {
  1209.     if (get_constisnull((Const) expression))
  1210.         *isNull = true;
  1211.  
  1212.         retDatum = get_constvalue((Const) expression);
  1213.     }
  1214.     
  1215.     else if (ExactNodeType(expression,Param))
  1216.     retDatum = (Datum)  ExecEvalParam((Param) expression, econtext, isNull);
  1217.    
  1218.     else if (ExactNodeType(expression,Iter))
  1219.     retDatum = (Datum)  ExecEvalIter((Iter) expression,
  1220.                      econtext,
  1221.                      isNull,
  1222.                      isDone);
  1223.    
  1224.     else if (ExactNodeType(expression,ArrayRef))
  1225.     retDatum = (Datum)  ExecEvalArrayRef((ArrayRef) expression,
  1226.                      econtext,
  1227.                      isNull,
  1228.                      isDone);
  1229.     else if (fast_is_clause(expression))    /* car is a Oper node */
  1230.     retDatum = (Datum) ExecEvalOper((List) expression, econtext, isNull);
  1231.     
  1232.     else if (fast_is_funcclause(expression))     /* car is a Func node */
  1233.     retDatum = (Datum) ExecEvalFunc((LispValue) expression,
  1234.                     econtext,
  1235.                     isNull,
  1236.                     isDone);
  1237.       
  1238.     else if (fast_or_clause(expression))
  1239.     retDatum = (Datum) ExecEvalOr((List) expression, econtext, isNull);
  1240.    
  1241.     else if (fast_and_clause(expression))
  1242.     retDatum = (Datum)  ExecEvalAnd((List) expression, econtext, isNull);
  1243.  
  1244.     else if (fast_not_clause(expression))
  1245.     retDatum = (Datum)  ExecEvalNot((List) expression, econtext, isNull);
  1246.  
  1247.     else
  1248.     elog(WARN, "ExecEvalExpr: unknown expression type");
  1249.  
  1250.     return retDatum;
  1251. }
  1252.  
  1253. /* ----------------------------------------------------------------
  1254.  *             ExecQual / ExecTargetList 
  1255.  * ----------------------------------------------------------------
  1256.  */
  1257.  
  1258. /* ----------------------------------------------------------------
  1259.  *        ExecQualClause
  1260.  *
  1261.  *    this is a workhorse for ExecQual.  ExecQual has to deal
  1262.  *    with a list of qualifications, so it passes each qualification
  1263.  *    in the list to this function one at a time.  ExecQualClause
  1264.  *    returns true when the qualification *fails* and false if
  1265.  *    the qualification succeeded (meaning we have to test the
  1266.  *    rest of the qualification)
  1267.  * ----------------------------------------------------------------
  1268.  */
  1269. /**** xxref:
  1270.  *           ExecQual
  1271.  ****/
  1272. bool
  1273. ExecQualClause(clause, econtext)
  1274.     List     clause;
  1275.     ExprContext econtext;
  1276. {
  1277.     Datum   expr_value;
  1278.     Datum   const_value;
  1279.     Boolean isNull;
  1280.     Boolean isDone;
  1281.  
  1282.     /*
  1283.      * pass isDone, but ignore it.  We don't iterate over multiple
  1284.      * returns in the qualifications.
  1285.      */
  1286.     expr_value = (Datum)
  1287.     ExecEvalExpr((Node) clause, econtext, &isNull, &isDone);
  1288.     
  1289.     /* ----------------
  1290.      *    this is interesting behaviour here.  When a clause evaluates
  1291.      *  to null, then we consider this as passing the qualification.
  1292.      *  it seems kind of like, if the qual is NULL, then there's no
  1293.      *  qual.. 
  1294.      * ----------------
  1295.      */
  1296.     if (isNull)
  1297.     return true;
  1298.     
  1299.     /* ----------------
  1300.      *  remember, we return true when the qualification fails..
  1301.      * ----------------
  1302.      */
  1303.     if (ExecCFalse(DatumGetInt32(expr_value)))
  1304.     return true;
  1305.     
  1306.     return false;
  1307. }
  1308.  
  1309. /* ----------------------------------------------------------------
  1310.  *        ExecQual
  1311.  *    
  1312.  *        Evaluates a conjunctive boolean expression and returns t
  1313.  *    iff none of the subexpressions are false (or null).
  1314.  * ----------------------------------------------------------------
  1315.  */
  1316.  
  1317. /**** xxref:
  1318.  *           ExecMergeJoin
  1319.  *           ExecNestLoop
  1320.  *           ExecResult
  1321.  *           ExecScan
  1322.  *         prs2StubTestTuple
  1323.  ****/
  1324. bool
  1325. ExecQual(qual, econtext)
  1326.     List       qual;
  1327.     ExprContext      econtext;
  1328. {
  1329.     List         clause;
  1330.     bool         result;
  1331.     MemoryContext    oldContext;
  1332.     GlobalMemory      qualContext;
  1333.     
  1334.     /* ----------------
  1335.      *    debugging stuff
  1336.      * ----------------
  1337.      */
  1338.     EV_printf("ExecQual: qual is ");
  1339.     EV_lispDisplay(qual);
  1340.     EV_printf("\n");
  1341.  
  1342.     IncrProcessed();
  1343.  
  1344.     /* ----------------
  1345.      *    return true immediately if no qual
  1346.      * ----------------
  1347.      */
  1348.     if (lispNullp(qual))
  1349.     return true;
  1350.     
  1351.     /* ----------------
  1352.      *  a "qual" is a list of clauses.  To evaluate the
  1353.      *  qual, we evaluate each of the clauses in the list.
  1354.      *
  1355.      *  ExecQualClause returns true when we know the qualification
  1356.      *  *failed* so we just pass each clause in qual to it until
  1357.      *  we know the qual failed or there are no more clauses.
  1358.      * ----------------
  1359.      */
  1360.     result = false;
  1361.     foreach (clause, qual) {
  1362.     result = ExecQualClause( CAR(clause), econtext);
  1363.     if (result == true)
  1364.         break;
  1365.     }
  1366.  
  1367.     /* ----------------
  1368.      *    if result is true, then it means a clause failed so we
  1369.      *  return false.  if result is false then it means no clause
  1370.      *  failed so we return true.
  1371.      * ----------------
  1372.      */
  1373.     if (result == true)
  1374.     return false;
  1375.     
  1376.     return true;
  1377. }
  1378.  
  1379. HeapTuple
  1380. ExecFormComplexResult(tlist, natts, tdesc, values, nulls)
  1381.     List            tlist;
  1382.     int             natts;
  1383.     TupleDescriptor tdesc;
  1384.     Datum           *values;
  1385.     char            *nulls;
  1386. {
  1387.     TupleDescriptor flatTd;
  1388.     Datum           *flatValues;
  1389.     char            *flatNulls;
  1390.     int             flatInd;
  1391.     int             flatNatts;
  1392.     int             complexInd;
  1393.     TupleTableSlot  *foundslots;
  1394.     TupleTableSlot  *slotbase;
  1395.     TupleTableSlot  slot;
  1396.     HeapTuple       resultTup;
  1397.     List            tlistP;
  1398.  
  1399.     slotbase = (TupleTableSlot *)palloc ((natts+1)*sizeof(TupleTableSlot));
  1400.     bzero(slotbase, ((natts+1)*sizeof(TupleTableSlot)));
  1401.     foundslots = slotbase;
  1402.  
  1403.     /*
  1404.      * we make two passes through the target list - one to figure
  1405.      * out just how many attributes we are dealing with and another
  1406.      * to get all the aforementioned attributes.
  1407.      */
  1408.     flatNatts = 0;
  1409.     complexInd = 0;
  1410.     foreach(tlistP, tlist)
  1411.     {
  1412.     List tle = CAR(tlistP);
  1413.     /*
  1414.      * Since we are dealing with a complex result we know that we
  1415.      * are not at the top of the plan tree and therefore we know
  1416.      * that we have only resdoms and expressions (i.e. no Fjoins)
  1417.      */
  1418.     if ( get_rescomplex((Resdom)tl_resdom(tle)) )
  1419.     {
  1420.         HeapTuple      tuple;
  1421.  
  1422.         slot  = (TupleTableSlot)values[complexInd];
  1423.         tuple =  (HeapTuple)ExecFetchTuple(slot);
  1424.         flatNatts += tuple->t_natts;
  1425.     }
  1426.     else
  1427.         flatNatts++;
  1428.  
  1429.     complexInd++;
  1430.     }
  1431.     flatTd = CreateTemplateTupleDesc(flatNatts);
  1432.     flatValues = (Datum *)palloc(flatNatts*sizeof(Datum));
  1433.     flatNulls = (char *)palloc(flatNatts*sizeof(char));
  1434.  
  1435.     complexInd = flatInd = 0;
  1436.     foreach(tlistP, tlist)
  1437.     {
  1438.     
  1439.     List tle = CAR(tlistP);
  1440.     /*
  1441.      * Since we are dealing with a complex result we know that we
  1442.      * are not at the top of the plan tree and therefore we know
  1443.      * that we have only resdoms and expressions (i.e. no Fjoins)
  1444.      */
  1445.     if ( get_rescomplex((Resdom)tl_resdom(tle)) )
  1446.     {
  1447.         int             i;
  1448.         HeapTuple       tuple;
  1449.         TupleDescriptor subDesc;
  1450.         Resdom          res   = (Resdom)tl_resdom(tle);
  1451.  
  1452.         slot  = (TupleTableSlot)values[complexInd];
  1453.         tuple =  (HeapTuple)ExecFetchTuple(slot);
  1454.         subDesc = ExecSlotDescriptor(slot);
  1455.         heap_deformtuple(tuple,
  1456.                  subDesc,
  1457.                  &flatValues[flatInd],
  1458.                  &flatNulls[flatInd]);
  1459.         *foundslots++ = slot;
  1460.         for (i = 0; i < tuple->t_natts; i++, flatInd++)
  1461.         {
  1462.         flatTd->data[flatInd] = (AttributeTupleForm)
  1463.             palloc(sizeof(AttributeTupleFormD));
  1464.         bcopy(subDesc->data[i],
  1465.               flatTd->data[flatInd],
  1466.               sizeof(AttributeTupleFormD));
  1467.         }
  1468.     }
  1469.     else
  1470.     {
  1471.         flatTd->data[flatInd] = (AttributeTupleForm)
  1472.             palloc(sizeof(AttributeTupleFormD));
  1473.  
  1474.         bcopy(tdesc->data[complexInd],
  1475.           flatTd->data[flatInd],
  1476.           sizeof(AttributeTupleFormD));
  1477.  
  1478.         flatValues[flatInd] = values[complexInd];
  1479.         flatInd++;
  1480.     }
  1481.     complexInd++;
  1482.     }
  1483.  
  1484.     resultTup = (HeapTuple)heap_formtuple(flatNatts,
  1485.                       flatTd,
  1486.                       flatValues,
  1487.                       flatNulls);
  1488.     /*
  1489.      * Be tidy and free up our constructed tuple descriptor and all slots
  1490.      * that we found.
  1491.      */
  1492.     for (flatInd = 0; flatInd < flatNatts; flatInd++)
  1493.     pfree(flatTd->data[flatInd]);
  1494.     pfree (flatTd);
  1495.     foundslots = slotbase;
  1496.     while ((slot = *foundslots) != (TupleTableSlot)NULL)
  1497.     {
  1498.     pfree(ExecFetchTuple(slot));
  1499.     pfree(slot);
  1500.     foundslots++;
  1501.     }
  1502.     pfree (slotbase);
  1503.     return resultTup;
  1504. }
  1505.  
  1506. int
  1507. ExecTargetListLength(targetlist)
  1508. {
  1509.     int len;
  1510.     List tl;
  1511.  
  1512.     len = 0;
  1513.     foreach (tl, targetlist) {
  1514.     List curTle = CAR(tl);
  1515.  
  1516.     if (tl_is_resdom(curTle))
  1517.         len++;
  1518.     else
  1519.         len += get_fj_nNodes((Fjoin)tl_node(curTle));
  1520.     }
  1521.     return len;
  1522. }
  1523. /* ----------------------------------------------------------------
  1524.  *        ExecTargetList
  1525.  *    
  1526.  *        Evaluates a targetlist with respect to the current
  1527.  *    expression context and return a tuple.
  1528.  * ----------------------------------------------------------------
  1529.  */
  1530.  
  1531. /**** xxref:
  1532.  *           ExecMergeJoin
  1533.  *           ExecNestLoop
  1534.  *           ExecResult
  1535.  *           ExecScan
  1536.  ****/
  1537. HeapTuple
  1538. ExecTargetList(targetlist, nodomains, targettype, values, econtext, isDone)
  1539.     List          targetlist;
  1540.     int          nodomains;
  1541.     TupleDescriptor     targettype;
  1542.     Pointer          values;
  1543.     ExprContext         econtext;
  1544.     bool        *isDone;
  1545. {
  1546.     char        nulls_array[64];
  1547.     bool        fjNullArray[64];
  1548.     bool        *fjIsNull;
  1549.     char        *np, *null_head;
  1550.     List         tl;
  1551.     List         tle;
  1552.     int            len;
  1553.     Expr         expr;
  1554.     Resdom              resdom;
  1555.     AttributeNumber    resind;
  1556.     Const         expr_value;
  1557.     Datum         constvalue;
  1558.     HeapTuple         newTuple;
  1559.     MemoryContext    oldContext;
  1560.     GlobalMemory      tlContext;
  1561.     Boolean        complexResult;
  1562.     Boolean         isNull;
  1563.  
  1564.     /* ----------------
  1565.      *    debugging stuff
  1566.      * ----------------
  1567.      */
  1568.     EV_printf("ExecTargetList: tl is ");
  1569.     EV_lispDisplay(targetlist);
  1570.     EV_printf("\n");
  1571.  
  1572.     /* ----------------
  1573.      * Return a dummy tuple if the targetlist is empty .
  1574.      * the dummy tuple is necessary to differentiate 
  1575.      * between passing and failing the qualification.
  1576.      * ----------------
  1577.      */
  1578.     if (lispNullp(targetlist)) {
  1579.     /* ----------------
  1580.      *    I now think that the only time this makes
  1581.      *    any sence is when we run a delete query.  Then
  1582.      *    we need to return something other than nil
  1583.      *    so we know to delete the tuple associated
  1584.      *      with the saved tupleid.. see what ExecutePlan
  1585.      *      does with the returned tuple.. -cim 9/21/89
  1586.      *
  1587.      *      It could also happen in queries like:
  1588.      *        retrieve (foo.all) where bar.a = 3
  1589.      *
  1590.      *      is this a new phenomenon? it might cause bogus behavior
  1591.      *      if we try to free this tuple later!! I put a hook in
  1592.      *      ExecProject to watch out for this case -mer 24 Aug 1992
  1593.      * ----------------
  1594.      */
  1595.     CXT1_printf("ExecTargetList: context is %d\n", CurrentMemoryContext);
  1596.     *isDone = true;
  1597.     return (HeapTuple) true;
  1598.     }
  1599.  
  1600.     /* ----------------
  1601.      *  allocate an array of char's to hold the "null" information
  1602.      *  only if we have a really large targetlist.  otherwise we use
  1603.      *  the stack.
  1604.      * ----------------
  1605.      */
  1606.     len = ExecTargetListLength(targetlist);
  1607.     
  1608.     if (len > 64) {
  1609.         np = (char *) palloc(len+1);
  1610.     fjIsNull = (bool *) palloc(len+1);
  1611.     } else {
  1612.     np = &nulls_array[0];
  1613.     fjIsNull = &fjNullArray[0];
  1614.     }
  1615.     
  1616.     null_head = np;
  1617.     bzero(np, len+1);
  1618.  
  1619.     /* ----------------
  1620.      *    evaluate all the expressions in the target list
  1621.      * ----------------
  1622.      */
  1623.     EV_printf("ExecTargetList: setting target list values\n");
  1624.  
  1625.     *isDone = true;
  1626.     complexResult = false;
  1627.     foreach (tl, targetlist) {
  1628.     /* ----------------
  1629.      *    remember, a target list is a list of lists:
  1630.      *
  1631.      *    ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
  1632.      *
  1633.      *    tl is a pointer to successive cdr's of the targetlist
  1634.      *    tle is a pointer to the target list entry in tl
  1635.      * ----------------
  1636.      */
  1637.     tle = CAR(tl);
  1638.     if (lispNullp(tle))
  1639.         break;
  1640.       
  1641.     if (tl_is_resdom(tle)) {
  1642.         expr       = (Expr)   tl_expr(tle);
  1643.         resdom     = (Resdom) tl_resdom(tle);
  1644.         resind     = get_resno(resdom) - 1;
  1645.         constvalue = (Datum) ExecEvalExpr((Node)expr,
  1646.                           econtext,
  1647.                           &isNull,
  1648.                           isDone);
  1649.  
  1650.         if ((ExactNodeType(expr,Iter)) && (*isDone))
  1651.         return (HeapTuple)NULL;
  1652.  
  1653.         if (get_rescomplex(resdom))
  1654.         complexResult = true;
  1655.  
  1656.         ExecSetTLValues(resind, values, constvalue);
  1657.     
  1658.         if (!isNull)
  1659.         null_head[resind] = ' ';
  1660.         else
  1661.         null_head[resind] = 'n';
  1662.     }
  1663.     else {
  1664.         int      curNode;
  1665.         Resdom   fjRes;
  1666.         List     fjTlist   = CDR(tle);
  1667.         Fjoin    fjNode    = (Fjoin)tl_node(tle);
  1668.          int      nNodes    = get_fj_nNodes(fjNode);
  1669.         DatumPtr results   = get_fj_results(fjNode);
  1670.  
  1671.         ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
  1672.         if (*isDone)
  1673.         return (HeapTuple)NULL;
  1674.  
  1675.         /*
  1676.          * get the result from the inner node
  1677.          */
  1678.         fjRes = (Resdom)CAR(get_fj_innerNode(fjNode));
  1679.         resind = get_resno(fjRes) - 1;
  1680.         if (fjIsNull[0])
  1681.         null_head[resind] = 'n';
  1682.         else
  1683.         {
  1684.         null_head[resind] = ' ';
  1685.         ExecSetTLValues(resind, values, results[0]);
  1686.         }
  1687.  
  1688.         /*
  1689.          * Get results from all of the outer nodes
  1690.          */
  1691.         for (curNode = 1;
  1692.          curNode < nNodes;
  1693.          curNode++, fjTlist = CDR(fjTlist))
  1694.         {
  1695.         fjRes = (Resdom)CAAR(fjTlist);
  1696.  
  1697.         resind = get_resno(fjRes) - 1;
  1698.         if (fjIsNull[curNode]) {
  1699.             null_head[resind] = 'n';
  1700.         }
  1701.         else
  1702.         {
  1703.             null_head[resind] = ' ';
  1704.                 ExecSetTLValues(resind, values, results[curNode]);
  1705.         }
  1706.         }
  1707.     }
  1708.     }
  1709.  
  1710.     /* ----------------
  1711.      *     form the new result tuple (in the "normal" context)
  1712.      * ----------------
  1713.      */
  1714.     if (complexResult)
  1715.     newTuple = (HeapTuple) ExecFormComplexResult(targetlist,
  1716.                              nodomains,
  1717.                              targettype,
  1718.                              values,
  1719.                              null_head);
  1720.     else
  1721.     newTuple = (HeapTuple)
  1722.         heap_formtuple(nodomains, targettype, values, null_head);
  1723.  
  1724.     /* ----------------
  1725.      *    free the nulls array if we allocated one..
  1726.      * ----------------
  1727.      */
  1728.     if (len > 64) pfree(null_head);
  1729.  
  1730.     return
  1731.     newTuple;
  1732. }
  1733.  
  1734. /* ----------------------------------------------------------------
  1735.  *        ExecProject
  1736.  *    
  1737.  *    projects a tuple based in projection info and stores
  1738.  *    it in the specified tuple table slot.
  1739.  *
  1740.  *    Note: someday soon the executor can be extended to eliminate
  1741.  *          redundant projections by storing pointers to datums
  1742.  *          in the tuple table and then passing these around when
  1743.  *          possible.  this should make things much quicker.
  1744.  *          -cim 6/3/91
  1745.  * ----------------------------------------------------------------
  1746.  */
  1747. TupleTableSlot
  1748. ExecProject(projInfo, isDone)
  1749.     ProjectionInfo projInfo;
  1750.     bool           *isDone;
  1751. {
  1752.     TupleTableSlot    slot;
  1753.     List          targetlist;
  1754.     List          tle;
  1755.     int          len;
  1756.     TupleDescriptor     tupType;
  1757.     Pointer          tupValue;
  1758.     ExprContext         econtext;
  1759.     HeapTuple        newTuple;
  1760.     
  1761.     /* ----------------
  1762.      *    sanity checks
  1763.      * ----------------
  1764.      */
  1765.     if (projInfo == NULL)
  1766.     return (TupleTableSlot) NULL;
  1767.     
  1768.     /* ----------------
  1769.      *  get the projection info we want
  1770.      * ----------------
  1771.      */
  1772.     slot =         get_pi_slot(projInfo);
  1773.     targetlist =     get_pi_targetlist(projInfo);
  1774.     len =         get_pi_len(projInfo);
  1775.     tupType =         ExecSlotDescriptor((Pointer) slot);
  1776.     
  1777.     tupValue =         get_pi_tupValue(projInfo);
  1778.     econtext =         get_pi_exprContext(projInfo);
  1779.     
  1780.     /* ----------------
  1781.      *  form a new (result) tuple
  1782.      * ----------------
  1783.      */
  1784.     newTuple = ExecTargetList(targetlist,
  1785.                   len,
  1786.                   tupType,
  1787.                   tupValue,
  1788.                   econtext,
  1789.                   isDone);
  1790.  
  1791.     /* ----------------
  1792.      *    store the tuple in the projection slot and return the slot.
  1793.      *
  1794.      *  If there's no projection target list we don't want to pfree
  1795.      *  the bogus tuple that ExecTargetList passes back to us.
  1796.      *       -mer 24 Aug 1992
  1797.      * ----------------
  1798.      */
  1799.     return (TupleTableSlot)
  1800.     ExecStoreTuple((Pointer) newTuple, /* tuple to store */
  1801.                (Pointer) slot,     /* slot to store in */
  1802.                InvalidBuffer,        /* tuple has no buffer */
  1803.                        /* ok to pfree this tuple */
  1804.                get_pi_targetlist(projInfo) ? true : false);
  1805. }
  1806.